<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>评论分析</title>
  <style>
    [v-cloak] {
      display: none;
    }

    .el-progress-bar__innerText {
      color: #585757 !important;
    }
  </style>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/echarts@5.1.2/dist/echarts.min.js"></script>
</head>

<body>
  <div id="app" v-cloak>
    <h3 style="margin: 25px 0 0;color: #408ad4;">
      <a style="font-size: 14px;float: right;margin-right: 20px;" target="_blank"
        :href="'https://aliexpress.com/item/'+productId+'.html'">去商品页面</a>
      评论分析
      <span style="color: gray;font-size: 14px;margin-left: 20px;font-weight: normal;">
        共{{totalLength}}条
      </span>
      <span style="color: gray;font-size: 14px;margin-left: 40px;font-weight: normal;">最早一条评论出现在 {{earliest}}</span>
    </h3>
    <el-divider></el-divider>
    <el-tabs v-model="activeTabs" type="card">
      <!-- 按国家 -->
      <el-tab-pane label="按国家" name="country">
        <div v-show="countryFilters.timeType === '全部'" class="block"
          style="float: right;margin-right: 50px;max-height: 800px;overflow: auto;">
          <div class="radio" style="margin-bottom: 20px;">
            时间线：
            <el-radio-group v-model="countryData.reverse">
              <el-radio :label="true">倒序</el-radio>
              <el-radio :label="false">正序</el-radio>
            </el-radio-group>
          </div>
          <p style="text-align:right;font-size: 12px;padding: 0 0 10px 0;color: gray;">近7个自然月，各个月数量</p>
          <el-timeline :reverse="!countryData.reverse">
            <el-timeline-item :color="activity.color" size="large" v-for="(activity, index) in timelineData"
              :key="index" :timestamp="activity.timestamp">
              {{activity.content}}
            </el-timeline-item>
          </el-timeline>
          <el-link @click="toggleViewFlag" style="color: 408ad4; font-size: 12px; float: right;" type="primary">看详情
          </el-link>
        </div>
        <el-select style="margin: 0 0 15px 15px;" v-model="countryFilters.userCountry" filterable>
          <el-option v-for="item in cCountrySelectionOpts" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
        <el-radio-group style="margin-left: 30px;" v-model="countryFilters.timeType">
          <el-radio-button label="全部"></el-radio-button>
          <el-radio-button label="最近3个月"></el-radio-button>
          <el-radio-button label="最近1个月"></el-radio-button>
        </el-radio-group>
        <el-select style="margin: 0 0 15px 15px;" v-model="countryFilters.star" filterable>
          <el-option v-for="item in starSelectionOpts" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
        <span style="margin-left:20px;font-size:12px;color: gray;">共{{cData.length}}条</span>
        <el-button size="small" style="float: right;margin-right: 25px;" @click="handleCopy">复制所选评论</el-button>
        <div>
          <el-table v-show="countryFilters.userCountry === 'ALL'"
            style="width: 450px; float: left; margin-right: 20px; margin-bottom: 10px;" max-height="650"
            :data="cCountryTable" fit border sortable stripe>
            <el-table-column prop="country" label="国家"></el-table-column>
            <el-table-column width="80" prop="countryCount" label="数量"></el-table-column>
            <el-table-column width="180" prop="percent" label="占比">
              <template slot-scope="scope">
                <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
              </template>
            </el-table-column>
          </el-table>
          <el-table style="width: 450px; float: left; margin-bottom: 10px;margin-right: 20px;" max-height="650"
            :data="cShipTable" border fit sortable stripe>
            <el-table-column prop="ship" label="物流方式"></el-table-column>
            <el-table-column width="80" prop="shipCount" label="数量"></el-table-column>
            <el-table-column width="180" prop="percent" label="占比">
              <template slot-scope="scope">
                <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
              </template>
            </el-table-column>
          </el-table>
          <el-table v-if="proAttrsData.proAttrs.length" style="width: 450px; float: left; margin-bottom: 10px;"
            max-height="650" :data="cMainAttrTable" border fit sortable stripe>
            <el-table-column prop="color" :label="proAttrsData.proAttrs[0]"></el-table-column>
            <el-table-column width="80" prop="colorCount" label="数量"></el-table-column>
            <el-table-column width="180" prop="percent" label="占比">
              <template slot-scope="scope">
                <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </el-tab-pane>
      <!-- 按物流 -->
      <el-tab-pane label="按物流" name="ship">
        <el-select style="margin: 0 0 15px 15px;" v-model="shipFilters.activeShip" filterable>
          <el-option v-for="item in sShipSelectionOpts" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
        <span style="margin-left:20px;font-size:12px;color: gray;">共{{sData.length}}条</span>
        <div>
          <el-table v-show="shipFilters.activeShip === 'ALL'"
            style="width: 400px; float: left; margin-right: 20px; margin-bottom: 10px;" max-height="650"
            :data="sShipTable" fit border sortable stripe>
            <el-table-column prop="ship" label="物流方式"></el-table-column>
            <el-table-column width="80" prop="shipCount" label="数量"></el-table-column>
            <el-table-column width="180" prop="percent" label="占比">
              <template slot-scope="scope">
                <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
              </template>
            </el-table-column>
          </el-table>
          <el-table style="width: 400px; float: left; margin-right: 20px; margin-bottom: 10px;" max-height="650"
            :data="sCountryTable" fit border sortable stripe>
            <el-table-column prop="country" label="国家"></el-table-column>
            <el-table-column width="80" prop="countryCount" label="数量"></el-table-column>
            <el-table-column width="180" prop="percent" label="占比">
              <template slot-scope="scope">
                <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </el-tab-pane>
      <!-- 属性详情 -->
      <el-tab-pane v-if="proAttrsData.proAttrs.length > 1" label="属性详情" name="attr">
        <el-select style="margin: 0 0 15px 15px;" v-model="proAttrsFilter.userCountry" filterable>
          <el-option v-for="item in pCountrySelectionOpts" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
        <span style="margin-left:20px;font-size:12px;color: gray;">共{{pData.length}}条</span>
        <div>
          <el-table style="width: 400px; float: left; margin-right: 20px; margin-bottom: 10px;" max-height="650"
            :data="pAttrsTable" fit border sortable stripe>
            <el-table-column prop="attr" label="属性组合"></el-table-column>
            <el-table-column width="80" prop="attrCount" label="数量"></el-table-column>
            <el-table-column width="180" prop="percent" label="占比">
              <template slot-scope="scope">
                <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
              </template>
            </el-table-column>
          </el-table>
          <div style="float: left;">
            <p>单属性分布：</p>
            <el-table v-for="(table, attr) in pAttrTableObj"
              style="width: 400px; float: left; margin-right: 20px; margin-bottom: 10px;" max-height="400" :data="table"
              fit border sortable stripe>
              <el-table-column :prop="attr" :label="attr"></el-table-column>
              <el-table-column width="80" :prop="attr + 'Count'" label="数量"></el-table-column>
              <el-table-column width="180" prop="percent" label="占比">
                <template slot-scope="scope">
                  <el-progress :text-inside="true" :stroke-width="12" :percentage="scope.row.percentNum"></el-progress>
                </template>
              </el-table-column>
            </el-table>
          </div>
        </div>
      </el-tab-pane>
    </el-tabs>
    <div v-show="viewFlag"
      style="z-index: 2;position: fixed;width: 100%;height: 100%;left: 0;top: 0;background-color: white;">
      <el-button icon="el-icon-arrow-left" style="float:left;margin: 20px;" @click="toggleViewFlag">返回</el-button>
      <p style="color:gray;text-align: center;margin-bottom: 50px;">折线图是为了看趋势，返评有滞后性，对近期的趋势判断影响极大，需要自己主观把握</p>
      <el-select style="margin: 0 0 15px 15px;" v-model="lineFilters.userCountry" filterable>
        <el-option v-for="item in cCountrySelectionOpts" :key="item.value" :label="item.label" :value="item.value">
        </el-option>
      </el-select>
      <el-radio-group style="margin-left: 30px;" v-model="lineFilters.type">
        <el-radio-button label="按日"></el-radio-button>
        <el-radio-button label="按月"></el-radio-button>
      </el-radio-group>
      <span
        style="font-weight: bold; font-size: 16px;margin-left: 230px;">{{lineFilters.type === '按日' ? '最近30天' : '最近7个自然月'}}</span>
      <div id="main" style="width: 100%;height:600px;"></div>
    </div>
  </div>
  <script>
    const dict = {
      "EU": "欧盟",
      "AF": "阿富汗",
      "AX": "奥兰群岛",
      "AL": "阿尔巴尼亚",
      "DZ": "阿尔及利亚",
      "AS": "美属萨摩亚",
      "AD": "安道尔",
      "AO": "安哥拉",
      "AI": "安圭拉",
      "AG": "安提瓜和巴布达",
      "AR": "阿根廷",
      "AM": "亚美尼亚",
      "AW": "阿鲁巴",
      "AU": "澳大利亚",
      "AT": "奥地利",
      "AZ": "阿塞拜疆",
      "BD": "孟加拉",
      "BH": "巴林",
      "BS": "巴哈马",
      "BB": "巴巴多斯",
      "BY": "白俄罗斯",
      "BE": "比利时",
      "BZ": "伯利兹",
      "BJ": "贝宁",
      "BM": "百慕大",
      "BT": "不丹",
      "BO": "玻利维亚",
      "BA": "波斯尼亚和黑塞哥维那",
      "BW": "博茨瓦纳",
      "BV": "布维岛",
      "BR": "巴西",
      "BN": "文莱",
      "BG": "保加利亚",
      "BF": "布基纳法索",
      "BI": "布隆迪",
      "KH": "柬埔寨",
      "CM": "喀麦隆",
      "CA": "加拿大",
      "CV": "佛得角",
      "CF": "中非",
      "TD": "乍得",
      "CL": "智利",
      "CX": "圣诞岛",
      "CC": "科科斯（基林）群岛",
      "CO": "哥伦比亚",
      "KM": "科摩罗",
      "CD": "刚果（金）",
      "CG": "刚果",
      "CK": "库克群岛",
      "CR": "哥斯达黎加",
      "CI": "科特迪瓦",
      "CN": "中国",
      "HR": "克罗地亚",
      "CU": "古巴",
      "CZ": "捷克",
      "CY": "塞浦路斯",
      "DK": "丹麦",
      "DJ": "吉布提",
      "DM": "多米尼加",
      "EC": "厄瓜多尔",
      "EG": "埃及",
      "GQ": "赤道几内亚",
      "ER": "厄立特里亚",
      "EE": "爱沙尼亚",
      "ET": "埃塞俄比亚",
      "FO": "法罗群岛",
      "FJ": "斐济",
      "FI": "芬兰",
      "FR": "法国",
      "FX": "法国大都会",
      "GF": "法属圭亚那",
      "PF": "法属波利尼西亚",
      "GA": "加蓬",
      "GM": "冈比亚",
      "GE": "格鲁吉亚",
      "DE": "德国",
      "GH": "加纳",
      "GI": "直布罗陀",
      "GR": "希腊",
      "GD": "格林纳达",
      "GP": "瓜德罗普岛",
      "GU": "关岛",
      "GT": "危地马拉",
      "GG": "根西岛",
      "GW": "几内亚比绍",
      "GN": "几内亚",
      "GY": "圭亚那",
      "HT": "海地",
      "HN": "洪都拉斯",
      "HU": "匈牙利",
      "IS": "冰岛",
      "IN": "印度",
      "ID": "印度尼西亚",
      "IR": "伊朗",
      "IQ": "伊拉克",
      "IE": "爱尔兰",
      "IM": "马恩岛",
      "IL": "以色列",
      "IT": "意大利",
      "JM": "牙买加",
      "JP": "日本",
      "JE": "泽西岛",
      "JO": "约旦",
      "KZ": "哈萨克斯坦",
      "KE": "肯尼亚",
      "KI": "基里巴斯",
      "KR": "韩国",
      "KP": "朝鲜",
      "KW": "科威特",
      "KG": "吉尔吉斯斯坦",
      "LO": "老挝",
      "LV": "拉脱维亚",
      "LB": "黎巴嫩",
      "LS": "莱索托",
      "LR": "利比里亚",
      "LY": "利比亚",
      "LI": "列支敦士登",
      "LT": "立陶宛",
      "LU": "卢森堡",
      "MK": "马其顿",
      "MW": "马拉维",
      "MY": "马来西亚",
      "MG": "马达加斯加",
      "MV": "马尔代夫",
      "ML": "马里",
      "MT": "马耳他",
      "MH": "马绍尔群岛",
      "MQ": "马提尼克岛",
      "MR": "毛里塔尼亚",
      "MU": "毛里求斯",
      "YT": "马约特",
      "MX": "墨西哥",
      "MF": "密克罗尼西亚",
      "MD": "摩尔多瓦",
      "MC": "摩纳哥",
      "MN": "蒙古",
      "ME": "黑山",
      "MS": "蒙特塞拉特",
      "MA": "摩洛哥",
      "MZ": "莫桑比克",
      "MM": "缅甸",
      "NA": "纳米比亚",
      "NR": "瑙鲁",
      "NP": "尼泊尔",
      "NL": "荷兰",
      "NC": "新喀里多尼亚",
      "NZ": "新西兰",
      "NI": "尼加拉瓜",
      "NE": "尼日尔",
      "NG": "尼日利亚",
      "NU": "纽埃",
      "NF": "诺福克岛",
      "NO": "挪威",
      "OM": "阿曼",
      "PK": "巴基斯坦",
      "PW": "帕劳",
      "PS": "巴勒斯坦",
      "PA": "巴拿马",
      "PG": "巴布亚新几内亚",
      "PE": "秘鲁",
      "PH": "菲律宾",
      "PN": "皮特凯恩群岛",
      "PL": "波兰",
      "PT": "葡萄牙",
      "PR": "波多黎各",
      "QA": "卡塔尔",
      "RE": "留尼汪岛",
      "RO": "罗马尼亚",
      "RW": "卢旺达",
      "RU": "俄罗斯联邦",
      "SH": "圣赫勒拿",
      "KN": "圣基茨和尼维斯",
      "LC": "圣卢西亚",
      "VG": "圣文森特和格林纳丁斯",
      "SV": "萨尔瓦多",
      "WS": "萨摩亚",
      "SM": "圣马力诺",
      "ST": "圣多美和普林西比",
      "SA": "沙特阿拉伯",
      "SN": "塞内加尔",
      "SC": "塞舌尔",
      "SL": "塞拉利昂",
      "SG": "新加坡",
      "RS": "塞尔维亚",
      "SK": "斯洛伐克",
      "SI": "斯洛文尼亚",
      "SB": "所罗门群岛",
      "SO": "索马里",
      "ZA": "南非",
      "ES": "西班牙",
      "LK": "斯里兰卡",
      "SD": "苏丹",
      "SR": "苏里南",
      "SZ": "斯威士兰",
      "SE": "瑞典",
      "CH": "瑞士",
      "SY": "叙利亚",
      "TJ": "塔吉克斯坦",
      "TZ": "坦桑尼亚",
      "TH": "泰国",
      "TT": "特立尼达和多巴哥",
      "TL": "东帝汶",
      "TG": "多哥",
      "TK": "托克劳",
      "TO": "汤加",
      "TN": "突尼斯",
      "TR": "土耳其",
      "TM": "土库曼斯坦",
      "TV": "图瓦卢",
      "UG": "乌干达",
      "UA": "乌克兰",
      "AE": "阿拉伯联合酋长国",
      "UK": "英国",
      "US": "美国",
      "UY": "乌拉圭",
      "UZ": "乌兹别克斯坦",
      "VU": "瓦努阿图",
      "VA": "梵蒂冈",
      "VE": "委内瑞拉",
      "VN": "越南",
      "WF": "瓦利斯群岛和富图纳群岛",
      "EH": "西撒哈拉",
      "YE": "也门",
      "YU": "南斯拉夫",
      "ZM": "赞比亚",
      "ZW": "津巴布韦"
    };

    data = data.filter(i => i.userCountry in dict);

    function getAttrCountryDict(attrStr) {
      return function (data) {
        const result = Object.create(null);
        data.map(i => i[attrStr]).forEach(i => {
          if (i in result) {
            result[i]++;
          } else {
            result[i] = 1;
          }
        });
        return result;
      };
    }

    const getCountryCountDict = getAttrCountryDict('userCountry');
    const getShipCountDict = getAttrCountryDict('logistics');
    const getColorCountDict = getAttrCountryDict('color');

    function getCountrySelectionOpts(userData = data) {
      const countryCountDict = getCountryCountDict(userData);
      const keys = Object.keys(countryCountDict);
      const total = Object.values(countryCountDict).reduce((p, n) => p + n);
      keys.sort((a, b) => countryCountDict[b] - countryCountDict[a]);
      const result = keys.map(i => {
        return {
          value: i,
          label: dict[i] + '\t(' + (countryCountDict[i] * 100 / total).toFixed(2) + '%)'
        };
      });
      result.unshift({ label: '全部国家', value: 'ALL' });
      return result;
    }

    function getShipSelectionOpts(userData = data) {
      const shipCountDict = getShipCountDict(userData);
      const keys = Object.keys(shipCountDict);
      const total = Object.values(shipCountDict).reduce((p, n) => p + n);
      keys.sort((a, b) => shipCountDict[b] - shipCountDict[a]);
      const result = keys.map(i => {
        return {
          value: i,
          label: i + '\t(' + (shipCountDict[i] * 100 / total).toFixed(2) + '%)'
        };
      });
      result.unshift({ label: '全部物流', value: 'ALL' });
      return result;
    }

    const starSelectionOpts = [
      { value: 'ALL', label: '全部星级' },
      { value: 'G', label: '好评（4-5星）' },
      { value: 'M', label: '中评（3星）' },
      { value: 'P', label: '差评（1-2星）' },
    ];

    function getProAttrs(userData = data) {
      const keys = ["userName", "memberDetailUrl", "userCountry", "star", "logistics", "timeNew", "feedback", "photos", "ships_from"];
      const list = Object.keys(userData[0]).filter(i => !keys.includes(i));
      const result = [];
      if (list.includes('color')) {
        result.push('color');
        list.splice(list.indexOf('color'), 1);
      } else if (list.includes('size')) {
        result.push('size');
        list.splice(list.indexOf('size'), 1);
      } else if (list.includes('capacity')) {
        result.push('capacity');
        list.splice(list.indexOf('capacity'), 1);
      }
      return result.concat(list);
    }

    const proAttrs = getProAttrs(data);

    function makeAttrCountDict(userData = data) {
      const result = Object.create(null);
      userData.forEach(item => {
        const valueHash = attrsValueHash(proAttrs.map(attr => item[attr]));
        if (valueHash in result) {
          result[valueHash]++;
        } else {
          result[valueHash] = 1;
        }
      })
      return result;
    }

    function attrsValueHash(attrValues) {
      return attrValues.join(' + ');
    }

    function makeTableByDict(userData = data, makeDictFn, attrStr) {
      const userDict = makeDictFn(userData);
      return Object.keys(userDict).map((i) => {
        const count = userDict[i];
        const total = Object.values(userDict).reduce((p, n) => p + n);
        return {
          [attrStr]: i,
          [attrStr + 'Count']: count,
          percent: (count * 100 / total).toFixed(2) + '%',
          percentNum: Number((count * 100 / total).toFixed(2))
        };
      }).sort((a, b) => b[attrStr + 'Count'] - a[attrStr + 'Count']);
    }

    function draw(opt) {
      const userData = opt && opt.data || data;
      const type = opt && opt.type || '按日';
      const myChart = echarts.init(document.getElementById('main'));

      const now = (function () {
        const result = Object.create(null);
        const now = new Date().toDateString();
        result.month = now.slice(4, 7);
        result.date = now.slice(8, 10);
        result.year = now.slice(-4);
        result.str = result.date + ' ' + result.month + ' ' + result.year;
        return result;
      })();

      const xAxis = (function () {
        let len = 30, str = now.str;
        const result = [];
        if (type === '按日') {
          result.push(now.str);
          while (len-- > 0) {
            str = getPrevDate(str)
            result.unshift(str);
          }
        } else {
          len = 7;
          str = now.str.slice(3, 11);
          result.push(str);
          while (len-- > 0) {
            str = getPrevMonthStr(str);
            result.unshift(str);
          }
        }
        return result;
      })();

      const yAxios = (function () {
        return xAxis.map(x => {
          return userData.filter(i => i.timeNew.includes(x)).length;
        });
      })();

      const option = {
        xAxis: {
          type: 'category',
          data: xAxis,
          boundaryGap: false,
          axisLabel: {
            rotate: 30
          }
        },
        yAxis: {
          type: 'value'
        },
        series: [{
          data: yAxios,
          type: 'line',
          smooth: 0.3
        }],
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            label: {
              backgroundColor: '#6a7985'
            }
          },
        }
      };

      // 使用刚指定的配置项和数据显示图表。
      myChart.setOption(option);
    }

    function getPrevDate(str) {
      const lastMonthIsShort = ['02', '04', '06', '08', '09', '11', '01'];
      const year = str.slice(7, 11);
      const month = str.slice(3, 6);
      const date = str.slice(0, 2);
      if (Number(date) > 10) {
        return (date - 1) + ' ' + month + ' ' + year;
      } else if (Number(date) > 1) {
        return '0' + (Number(date) - 1) + ' ' + month + ' ' + year;
      } else {
        if (lastMonthIsShort.includes(month)) {
          return '31' + ' ' + getPrevMonthStr(str.slice(3, 11));
        } else if (month !== '03') {
          return '30' + ' ' + getPrevMonthStr(str.slice(3, 11));
        } else if (isLeap(year)) {
          return '28' + ' ' + getPrevMonthStr(str.slice(3, 11));
        } else {
          return '29' + ' ' + getPrevMonthStr(str.slice(3, 11));
        }
      }
    }

    function isLeap(year) {
      return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }

    function getPrevMonthStr(str) {
      const monthSort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
      const month = str.slice(0, 3);
      if (month === 'Jan') {
        return 'Dec ' + Number(str.slice(-4) - 1);
      } else {
        return monthSort[monthSort.indexOf(month) - 1] + ' ' + str.slice(-4);
      }
    }

    new Vue({
      el: '#app',
      data() {
        return {
          earliest: '',
          viewFlag: false,
          productId,
          countryFilters: {
            userCountry: 'ALL',
            timeType: '全部',
            star: 'ALL'
          },
          countryData: {
            reverse: true,
          },
          shipFilters: {
            activeShip: 'ALL'
          },
          activeTabs: 'country',
          starSelectionOpts,
          proAttrsData: { proAttrs },
          proAttrsFilter: {
            userCountry: 'ALL'
          },
          lineFilters: {
            userCountry: 'ALL',
            type: '按日'
          },
          lineData: {
            renderData: this.cData,
          }
        }
      },
      watch: {
        'lineFilters': {
          handler(newVal) {
            const { timeType, userCountry } = newVal;
            const data = this.filterDataBy({ userCountry: this.lineFilters.userCountry });
            draw({ data, type: newVal.type });
          },
          deep: true
        }
      },
      computed: {
        cCountrySelectionOpts() {
          const o = { ...this.countryFilters }
          delete o.userCountry;
          const userData = this.filterDataBy(o);
          return getCountrySelectionOpts(userData);
        },
        totalLength() {
          return data.length;
        },
        timelineData() {
          return this.genTimeLineData(this.cData);
        },
        cCountryTable() {
          return this.getCountryDataBy(this.cData);
        },
        cShipTable() {
          return this.getShipTableDataBy(this.cData);
        },
        cMainAttrTable() {
          return this.getMainAttrTableDataBy(this.cData);
        },
        cData() {
          return this.filterDataBy(this.countryFilters);
        },
        sCountryTable() {
          return this.getCountryDataBy(this.sData);
        },
        sShipTable() {
          return this.getShipTableDataBy(this.sData);
        },
        sShipSelectionOpts() {
          return getShipSelectionOpts(data);
        },
        sData() {
          return this.filterDataBy(this.shipFilters);
        },
        pAttrsTable() {
          return this.getAttrsDataBy(this.pData);
        },
        pAttrTableObj() {
          return this.getAttrTablesObjBy(this.pData);
        },
        pCountrySelectionOpts() {
          return getCountrySelectionOpts(data);
        },
        pData() {
          return this.filterDataBy(this.proAttrsFilter);
        }
      },
      created() {
        this.earliest = data.slice(0).sort((a, b) => new Date(a.timeNew).getTime() - new Date(b.timeNew).getTime())[0].timeNew;
      },
      methods: {
        getAttrTablesObjBy(userData = data) {
          const result = Object.create(null);
          proAttrs.forEach(i => {
            const table = makeTableByDict(userData, getAttrCountryDict(i), i);
            result[i] = table;
          });
          return result;
        },
        getAttrsDataBy(userData = data) {
          return makeTableByDict(userData, makeAttrCountDict, 'attr');
        },
        getCountryDataBy(userData = data) {
          return makeTableByDict(userData, getCountryCountDict, 'country').map(i => {
            i.country = dict[i.country];
            return i;
          });
        },
        getMainAttrTableDataBy(userData = data) {
          return makeTableByDict(userData, getAttrCountryDict(proAttrs[0]), 'color');
        },
        getShipTableDataBy(userData = data) {
          return makeTableByDict(userData, getShipCountDict, 'ship');
        },
        genTimeLineData(data) {
          const d = new Date();
          const MAX = 7;
          let len = d.getDate() > 9 ? MAX : MAX + 1;
          const result = [];
          const str = String(d);
          let timeStr = str.slice(4, 7) + ' ' + str.slice(11, 15);
          while (len-- > 0) {
            const num = getCountByMonth(timeStr);
            const percent = (num * 100 / data.length).toFixed(2);
            const color = percent > 80
              ? '#e35141'
              : percent > 60
                ? '#d56353'
                : percent > 40
                  ? '#d87f4c'
                  : percent > 20
                    ? '#eecb66'
                    : '#59b39e';
            result.push({
              content: '评论数: ' + num + '  =>  ' + percent + '%',
              timestamp: timeStr,
              color: num > 0 ? color : ''
            });
            timeStr = getPrevMonthStr(timeStr);
          }
          return result;

          function getCountByMonth(monthStr) {
            return data.filter(i => i.timeNew.slice(3, 11) === monthStr).length;
          }
        },
        handleCopy() {
          let content = '';
          if (this.activeTabs === 'country') {
            content = this.cData.map(i => i.feedback).filter(i => i).join('\n');
          }
          const aux = document.createElement("textarea");
          aux.value = content;
          document.body.appendChild(aux);
          aux.select();
          document.execCommand("copy");
          document.body.removeChild(aux);
          this.$message({ message: '已复制', type: 'success' });
        },
        filterDataBy(filterObj, userData = data) {
          const list = Object.keys(filterObj).filter(i => filterObj[i] !== 'ALL' && filterObj[i] !== '全部');
          let result = userData;
          if (list.includes('timeType')) {
            result = this.filterDataByTimeType(filterObj.timeType, result);
          }
          if (list.includes('userCountry')) {
            result = this.filterDataByUserCountry(filterObj.userCountry, result);
          }
          if (list.includes('activeShip')) {
            result = this.filterDataByShip(filterObj.activeShip, result);
          }
          if (list.includes('star')) {
            result = this.filterDataByStar(filterObj.star, result);
          }
          return result;
        },
        filterDataByShip(ship, userData = data) {
          return userData.filter(i => i.logistics === ship);
        },
        filterDataByStar(star, userData = data) {
          if (star === 'G') {
            return userData.filter(i => i.star >= 4);
          }
          if (star === 'P') {
            return userData.filter(i => i.star <= 2);
          }
          return userData.filter(i => i.star === 3);
        },
        filterDataByUserCountry(country, userData = data) {
          return userData.filter(i => i.userCountry === country);
        },
        filterDataByTimeType(type, userData = data) {
          let timestamp = 0, now = new Date().getTime();
          if (type === '最近3个月') {
            timestamp = now - 3 * 30 * 24 * 3600 * 1000;
          } else if (type === '最近1个月') {
            timestamp = now - 1 * 30 * 24 * 3600 * 1000;
          }
          return userData.filter(i => new Date(i.timeNew).getTime() - timestamp >= 0);
        },
        toggleViewFlag() {
          this.viewFlag = !this.viewFlag;
          if (this.viewFlag) {
            setTimeout(() => {
              draw({ data: this.lineData.renderData, type: this.lineFilters.type });
            }, 0);
          }
        }
      }
    })
  </script>
</body>

</html>